package com.example;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;


public class NettyClientRetry {
    private static final int MAX_RETRY=10;
    private static final long RETRY_INTERVAL=2;
    private static Channel CHANNEL;

    public static void main(String[] args) throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup group = new NioEventLoopGroup();

        bootstrap
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline().addLast(new StringEncoder());
                    }
                });

        bootstrap.attr(AttributeKey.newInstance("clientName"),"client");

        /**
         * ChannelOption.CONNECT_TIMEOUT_MILLIS表示连接的超时时间，超过这个时间，如果仍未连接到服务端，则表示连接失败。
         * ChannelOption.SO_KEEPALIVE表示是否开启TCP底层心跳机制，true表示开启。
         * ChannelOption.TCP_NODELAY表示是否开始Nagle算法，true表示关闭，false表示开启。
         * 通俗地说，如果要求高实时性，有数据发送时就马上发送，就设置为true；如果需要减少发送次数，减少网络交互，就设置为false
         */
        bootstrap
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,5000)
                .option(ChannelOption.SO_KEEPALIVE,true)
                .option(ChannelOption.TCP_NODELAY,true);


        //建立连接
        final Channel channel = connect(bootstrap, "127.0.0.1", 8000, 0);

        while (true){
            channel.writeAndFlush(LocalDateTime.now()+": hello world");
            TimeUnit.SECONDS.sleep(2);
        }
    }

    private static Channel connect(Bootstrap bootstrap,String host,int port,int order){
         return bootstrap.connect(host, port)
                .addListener(future -> {
                    if (future.isSuccess()) {
                        System.out.println("连接成功");
                    } else if (MAX_RETRY == order) {
                        System.out.println("连接失败,放弃重连,重连次数: " + order);
                    } else {
                        System.out.println(LocalDateTime.now() + ": 连接失败,准备重连,重连次数: " + order);
                        bootstrap.config().group().schedule(
                            ()-> connect(bootstrap, host, port, order + 1),
                                RETRY_INTERVAL,TimeUnit.SECONDS
                        );
                    }
                })
                .channel();
    }
}
